﻿using System;
using System.Collections.Generic;
 
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;

namespace MapReduce.Services
{
    public class ExecuteMapService2 : ExecuteJobService2<String>{}
    public class ExecuteReduceService2 : ExecuteJobService2<List<String>> { }

    public class ExecuteJobService2<T> : IService
    {

        private byte[][] InnerExecute(Object pJobObj, byte[][] pData)
        {
            IJob<T> j = (IJob<T>)pJobObj;

            List<KeyValuePair<String, String>> outputList = new List<KeyValuePair<string, string>>();
            for (int i = 3; i < pData.Length; i+=2)
            {
                String key = U.Convert(pData[i]).ToString();
                T valObj = (T)U.Deserialize(pData[i+1]);

                outputList.AddRange(j.Execute(key, valObj));

            }//for i

            return new byte[][] { U.Serialize(outputList) };

        }//InnerExecute


        public byte[][] Execute(byte[][] pData)
        {
            
            byte[] assemblyArr = pData[0];
            String assemblyName = U.Convert(pData[1]).ToString();
            String className = U.Convert(pData[2]).ToString();


            //Save assembly
            String tmpDir = U.MapPath("Temp");
            if (!Directory.Exists(tmpDir)) Directory.CreateDirectory(tmpDir);

            assemblyName = Path.Combine(tmpDir, Guid.NewGuid().ToString() + assemblyName);

            File.WriteAllBytes(assemblyName, assemblyArr);

            Assembly asm = Assembly.LoadFrom(assemblyName);
            Object jobObj = asm.CreateInstance(className);

            byte[][] returnData = InnerExecute(jobObj, pData);
            
            try
            {
                File.Delete(assemblyName);
            }
            catch { }

            return returnData;

        }//Execute
    }//ExecuteJobService2


}
